package com.nuc.seckill.security.config;


import com.nuc.seckill.security.filter.FormUsernamePasswordFilter;
import com.nuc.seckill.security.filter.JsonUsernamePasswordFilter;
import com.nuc.seckill.security.filter.TokenFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;

/**
 * @author spider
 */
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserDetailsService userDetailsService;
    @Resource
    private AuthenticationSuccessHandler jsonLoginSuccessHandler;
    @Resource
    private AuthenticationSuccessHandler formLoginSuccessHandler;
    @Resource
    private AuthenticationFailureHandler authenticationFailureHandler;
    @Resource
    private LogoutSuccessHandler logoutSuccessHandler;
    @Resource
    private TokenFilter tokenFilter;
    @Resource
    private AuthenticationEntryPoint authenticationEntryPoint;
    @Resource
    private AccessDeniedHandler accessDeniedHandler;


    public static void main(String[] args) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode("123456");
        System.out.println(encode);
    }

    /**
     * 鉴权
     *
     * @param http http
     * @author 石一歌
     * @date 2022/8/9 23:25
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/product/**").hasAuthority("ADMIN")
                .antMatchers("/admin/**").hasAuthority("SUPERADMIN")
                .antMatchers("/login", "/user/**", "/public/**").permitAll();
        http.authorizeRequests()
                .anyRequest()
                .authenticated();
        http.exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler);
        http.cors();
        http.csrf().disable();

        http.logout().logoutUrl("/user/logout").logoutSuccessHandler(logoutSuccessHandler);
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.addFilterAt(jsonUsernamePasswordFilter(),
                UsernamePasswordAuthenticationFilter.class);
        http.addFilterAt(formUsernamePasswordFilter(),
                JsonUsernamePasswordFilter.class);
        http.addFilterBefore(tokenFilter, JsonUsernamePasswordFilter.class);
    }

    /**
     * 认证资源
     *
     * @param auth 授权建造器
     * @author 石一歌
     * @date 2022/8/9 23:24
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    /**
     * 静态资源
     *
     * @param web web
     * @author 石一歌
     * @date 2022/8/9 23:25
     */
    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers("/static", "/static/**")
                .antMatchers("/commons");
    }

    /**
     * 加密方式
     *
     * @return org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
     * @author 石一歌
     * @date 2022/8/9 23:26
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * json认证过滤器
     *
     * @return com.nuc.seckill.security.filter.JsonUsernamePasswordFilter
     * @author 石一歌
     * @date 2022/8/9 23:26
     */
    @Bean
    public JsonUsernamePasswordFilter jsonUsernamePasswordFilter() throws Exception {
        JsonUsernamePasswordFilter filter = new JsonUsernamePasswordFilter();
        filter.setAuthenticationSuccessHandler(jsonLoginSuccessHandler);
        filter.setAuthenticationFailureHandler(authenticationFailureHandler);
        filter.setFilterProcessesUrl("/user/login");
        filter.setAuthenticationManager(authenticationManagerBean());
        return filter;
    }

    /**
     * 表单认证过滤器
     *
     * @return com.nuc.seckill.security.filter.FormUsernamePasswordFilter
     * @author 石一歌
     * @date 2022/8/9 23:26
     */
    @Bean
    public FormUsernamePasswordFilter formUsernamePasswordFilter() throws Exception {
        FormUsernamePasswordFilter filter = new FormUsernamePasswordFilter();
        filter.setAuthenticationSuccessHandler(formLoginSuccessHandler);
        filter.setAuthenticationFailureHandler(authenticationFailureHandler);
        filter.setFilterProcessesUrl("/user/loginPage");
        filter.setAuthenticationManager(authenticationManagerBean());
        return filter;
    }

    /**
     * 跨域
     *
     * @return org.springframework.web.cors.CorsConfigurationSource
     * @author 石一歌
     * @date 2022/8/9 23:26
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
        corsConfiguration.setAllowedMethods(Arrays.asList("PUT", "DELETE", "GET", "POST", "OPTIONS"));
        corsConfiguration.setAllowedHeaders(Collections.singletonList("*"));
        corsConfiguration.setExposedHeaders(Arrays.asList("access-control-allow-headers",
                "access-control-allow-methods",
                "access-control-allow-origin",
                "access-control-max-age",
                "X-Frame-Options"));
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setMaxAge(3600L);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return source;
    }

}
